﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;

namespace WPFSchematics.Graphics.Ghosts
{
    /// <summary>
    /// 幻影观察器。用于观察宿主对象的幻影状态。
    /// 其中幻影状态特指那些已经注册到观察者中的普通依赖属性，
    /// 以及集合依赖属性中的集合成员对象。
    /// </summary>
    public class GhostObserver
    {
        /// <summary>
        /// 开始截取幻影事件。
        /// </summary>
        public event EventHandler SnapGhostBegin;

        /// <summary>
        /// 停止截取幻影事件。
        /// </summary>
        public event EventHandler SnapGhostEnd;

        /// <summary>
        /// 宿主对象(被观察对象)。
        /// </summary>
        public IGhostHost GhostHost { get; private set; }

        /// <summary>
        /// 宿主对象中被观察的依赖属性集合。
        /// </summary>
        public List<GhostProperty> GhostProperties { get; private set; }

        /// <summary>
        /// 幻影对象。
        /// </summary>
        private GhostObject _ghost;

        /// <summary>
        /// 新对象。
        /// </summary>
        public DependencyObject NewObject { get; set; }

        /// <summary>
        /// 是否截取幻影过程中。
        /// </summary>
        public bool IsSnapping
        {
            get { return _ghost != null; }
        }

        /// <summary>
        /// 是否恢复幻影过程中。
        /// </summary>
        public bool IsRestoring { get; private set;}

        /// <summary>
        /// 开始恢复幻影。
        /// </summary>
        internal void BeginRestore()
        {
            IsRestoring = true;
        }

        /// <summary>
        /// 结束恢复幻影。
        /// </summary>
        internal void EndRestore()
        {
            IsRestoring = false;
        }

        /// <summary>
        /// 开始截取幻影。
        /// </summary>
        public void BeginSnapGhost()
        {
            _ghost =new GhostObject {ObserverHost = GhostHost};
            if(SnapGhostBegin!=null)
            {
                SnapGhostBegin(this, null);
            }
            foreach (var observer in GhostProperties.Where(ghostProperty => ghostProperty.Type == GhostProperytType.Static).SelectMany(ghostProperty => ghostProperty.ChildObservers))
            {
                observer.BeginSnapGhost();
            }
        }

        /// <summary>
        /// 停止截取幻影。
        /// </summary>
        /// <returns></returns>
        public GhostObject EndSnapGhost()
        {
            if (_ghost == null) return null;

            var ghost = _ghost;

            _ghost = null;

            var e = ghost.ChildProperties.GetEnumerator();

            while (e.MoveNext())
            {
                var kv = e.Current;
                kv.Value.NewValue = ((DependencyObject)GhostHost).GetValue(kv.Key);
            }

            foreach (var g in from ghostProperty in GhostProperties where ghostProperty.Type == GhostProperytType.Static from observer in ghostProperty.ChildObservers select observer.EndSnapGhost() into g where g != null && g.Type == GhostType.Changed select g)
            {
                ghost.ChildRestores.Add(new GhostRestore(g));
            }

            if (SnapGhostEnd != null)
            {
                SnapGhostEnd(this, null);
            }

            return ghost.IsValid ? ghost : null;
        }

        /// <summary>
        /// 幻影属性集合中是否包含指定依赖属性。
        /// </summary>
        /// <param name="property">依赖属性。</param>
        /// <returns>true，存在；false，不存在。</returns>
        public bool Contains(DependencyProperty property)
        {
            return GhostProperties.Any(ghostProperty => ghostProperty.Property == property);
        }

        /// <summary>
        /// 获取包含指定依赖的幻影属性。
        /// </summary>
        /// <param name="property">依赖属性。</param>
        /// <returns>幻影属性。</returns>
        public GhostProperty GetGhostProperty(DependencyProperty property)
        {
            return GhostProperties.FirstOrDefault(ghostProperty => ghostProperty.Property == property);
        }

        /// <summary>
        /// 即时截取幻影。
        /// </summary>
        /// <param name="snapMode">截取模式。true，全部截取；false，仅记录关系。</param>
        /// <returns></returns>
        public GhostObject SnapGhost(bool snapMode)
        {
            var ghost = new GhostObject {ObserverHost = GhostHost, SnapMode = snapMode};
            if (snapMode)
            {
                foreach (var ghostProperty in GhostProperties)
                {
                    switch (ghostProperty.Type)
                    {
                        case GhostProperytType.Base:
                            var tupleValues = new TupleValues(((DependencyObject)GhostHost).GetValue(ghostProperty.Property));
                            tupleValues.NewValue = tupleValues.OldValue;
                            ghost.ChildProperties.Add(ghostProperty.Property, tupleValues);
                            break;
                        case GhostProperytType.Static:
                            foreach (var g in ghostProperty.ChildObservers.Select(observer => observer.SnapGhost(true)))
                            {
                                g.CollectionPropertyOwner = GhostHost;
                                g.CollectionProperty = ghostProperty.Property;
                                ghost.ChildRestores.Add(new GhostRestore(g));
                            }
                            break;
                        case GhostProperytType.Dynamic:
                            foreach (var g in ghostProperty.ChildObservers.Select(observer => observer.SnapGhost(false)))
                            {
                                g.CollectionPropertyOwner = GhostHost;
                                g.CollectionProperty = ghostProperty.Property;
                                ghost.ChildRestores.Add(new GhostRestore(g));
                            }
                            break;
                    }
                }
            }
            return ghost;
        }
        
        /// <summary>
        /// 被观察属性变更处理。
        /// </summary>
        /// <param name="e"></param>
        public virtual void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            if (_ghost == null || _ghost.Type != GhostType.Changed || !Contains(e.Property) || _ghost.ChildProperties.ContainsKey(e.Property))
                return;
            _ghost.ChildProperties.Add(e.Property, new TupleValues(e.OldValue));
        }

        /// <summary>
        /// 注册被观察属性。
        /// </summary>
        /// <param name="property"></param>
        /// <param name="type"></param>
        public void RegisterProperty(DependencyProperty property,GhostProperytType type)
        {
            var ghostProperty = GetGhostProperty(property);
            if (ghostProperty != null)
            {
                GhostProperties.Remove(ghostProperty);               
            }
            //if (!Contains(property))
            {
                ghostProperty  = new GhostProperty {Type = type, Observer = this, Property = property};
                GhostProperties.Add(ghostProperty);
            }
        }

        /// <summary>
        /// 注册被观察集合属性其成员的观察者。
        /// </summary>
        /// <param name="collectionProperty"></param>
        /// <param name="childObserver"></param>
        /// <param name="index"></param>
        public void AddChildGhostObserver(DependencyProperty collectionProperty, GhostObserver childObserver,int index)
        {
            var ghostProperty = GetGhostProperty(collectionProperty);
            if (ghostProperty == null || ghostProperty.ChildObservers.Contains(childObserver)) return;
            if (index > -1)
                ghostProperty.ChildObservers.Insert(index, childObserver);
            else
                ghostProperty.ChildObservers.Add(childObserver);
            //if (ghostProperty.Type == GhostProperytType.Static && childObserver.GhostProperties.Count < 1)
            //{
            //    childObserver.GhostHost.RegisterGhostProperty();
            //}
            if (_ghost == null) return;
            var ghost = childObserver.SnapGhost(ghostProperty.Type == GhostProperytType.Static);
            ghost.Type = GhostType.Added;
            /******/
            ghost.Index = index;
            ghost.CollectionPropertyOwner = GhostHost;
            ghost.CollectionProperty = collectionProperty;
            _ghost.ChildRestores.Add(new GhostRestore(ghost));
            childObserver.BeginSnapGhost();
        }

        /// <summary>
        /// 注销被观察集合属性其成员的观察者。
        /// </summary>
        /// <param name="collectionProperty"></param>
        /// <param name="childObserver"></param>
        /// <param name="index"></param>
        public void RemoveChildGhostObserver(DependencyProperty collectionProperty, GhostObserver childObserver,int index)
        {
            var ghostProperty = GetGhostProperty(collectionProperty);
            if (ghostProperty == null || !ghostProperty.ChildObservers.Contains(childObserver)) return;
            ghostProperty.ChildObservers.Remove(childObserver);
            if (_ghost == null) return;
            var ghost = childObserver.EndSnapGhost();
            if (ghost != null && ghost.IsValid)
            {
               _ghost.ChildRestores.Add(new GhostRestore(ghost)); 
            }
            ghost = childObserver.SnapGhost(ghostProperty.Type == GhostProperytType.Static);
            ghost.Type = GhostType.Deleted;
            /******/
            ghost.Index = index;
            ghost.CollectionPropertyOwner = GhostHost;
            ghost.CollectionProperty = collectionProperty;

            _ghost.ChildRestores.Add(new GhostRestore(ghost));
        }

        /// <summary>
        /// 构造。
        /// </summary>
        /// <param name="hostObject"></param>
        public GhostObserver(IGhostHost hostObject)
        {
            if (hostObject == null) return;
            IsRestoring = false;
            NewObject = null;
            GhostProperties = new List<GhostProperty>();
            GhostHost = hostObject;
        }
    }

    /// <summary>
    /// 幻影属性。用于在幻影观察者中维护被观察的依赖属性。
    /// </summary>
    public sealed class GhostProperty
    {
        /// <summary>
        /// 属性类型。
        /// </summary>
        public GhostProperytType Type { get; set; }

        /// <summary>
        /// 被观察的依赖属性。
        /// </summary>
        public DependencyProperty Property { get; set; }

        /// <summary>
        /// 所属观察器。
        /// </summary>
        public GhostObserver Observer { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public GhostProperty()
        {
            ChildObservers = new List<GhostObserver>();
        }

        /// <summary>
        /// 成员依赖属性集合。
        /// </summary>
        public List<GhostObserver> ChildObservers { get; private set; }
    }

    /// <summary>
    /// 幻影属性类型。
    /// </summary>
    public enum GhostProperytType
    { 
        /// <summary>
        /// 基础依赖属性。
        /// </summary>
        Base,
        /// <summary>
        /// 静态集合依赖属性。
        /// </summary>
        Static,
        /// <summary>
        /// 动态集合依赖属性。
        /// </summary>
        Dynamic
    }
}
